package com.yupi.springbootinit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yupi.springbootinit.mapper.ProcessBatchMapper;
import com.yupi.springbootinit.mapper.ProcessBatchStepMapper;
import com.yupi.springbootinit.mapper.ProductionOperationRecordMapper;
import com.yupi.springbootinit.mapper.WorkflowTaskMapper;
import com.yupi.springbootinit.model.entity.ProcessBatchStep;
import com.yupi.springbootinit.model.entity.ProductionOperationRecord;
import com.yupi.springbootinit.model.entity.WorkflowTask;
import com.yupi.springbootinit.model.vo.WorkflowTaskVO;
import com.yupi.springbootinit.model.vo.production.ProductionProgressVO;
import com.yupi.springbootinit.service.ProductionProgressService;
import com.yupi.springbootinit.utils.JsonUtils;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 生产进度服务实现
 */
@Slf4j
@Service
public class ProductionProgressServiceImpl implements ProductionProgressService {

    // ==================== 常量定义 ====================
    private static final String EXEC_CLEANING = "PREP_CLEANING";
    private static final String EVT_START = "START";
    private static final String EVT_COMPLETE = "COMPLETE";
    private static final String STEP_STATUS_COMPLETED = "COMPLETED";

    // ==================== 依赖注入 ====================
    @Resource
    private WorkflowTaskMapper workflowTaskMapper;
    @Resource
    private ProcessBatchStepMapper processBatchStepMapper;
    @Resource
    private ProductionOperationRecordMapper productionOperationRecordMapper;

    // ==================== 接口实现 ====================

    @Override
    public ProductionProgressVO getTaskProgress(Long taskId) {
        if (taskId == null) {
            return null;
        }

        Map<Long, ProductionProgressVO> resultMap = batchGetTaskProgress(Collections.singletonList(taskId));
        return resultMap.get(taskId);
    }

    @Override
    public Map<Long, ProductionProgressVO> batchGetTaskProgress(List<Long> taskIds) {
        Map<Long, ProductionProgressVO> result = new HashMap<>();
        if (taskIds == null || taskIds.isEmpty()) {
            return result;
        }

        // 1. 批量查任务与 batchId
        List<WorkflowTask> taskEntities = workflowTaskMapper.selectBatchIds(taskIds);
        Map<Long, WorkflowTask> taskMap = taskEntities.stream()
                .collect(Collectors.toMap(WorkflowTask::getId, t -> t, (a, b) -> a));

        Map<Long, Long> taskIdToBatchId = new HashMap<>();
        for (Long tid : taskIds) {
            WorkflowTask entity = taskMap.get(tid);
            taskIdToBatchId.put(tid, extractBatchIdFromTask(entity));
        }

        List<Long> batchIds = taskIdToBatchId.values().stream()
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        // 2. 批量查清机记录
        Map<Long, CleaningAgg> cleaningAggMap = batchQueryCleaningAgg(taskIds);

        // 3. 批量查步骤
        Map<Long, StepAgg> stepAggMap = batchQueryStepAgg(batchIds);

        // 4. 组装 VO
        for (Long taskId : taskIds) {
            ProductionProgressVO vo = new ProductionProgressVO();

            // 清机信息
            CleaningAgg cleaningAgg = cleaningAggMap.get(taskId);
            ProductionProgressVO.CleaningInfo cleaningInfo = new ProductionProgressVO.CleaningInfo();

            if (cleaningAgg == null || cleaningAgg.getStartTime() == null) {
                cleaningInfo.setStatus("NONE");
            } else {
                if (cleaningAgg.getEndTime() != null) {
                    cleaningInfo.setStatus("COMPLETED");
                    cleaningInfo.setEndTime(cleaningAgg.getEndTime());
                } else {
                    cleaningInfo.setStatus("IN_PROGRESS");
                }
                cleaningInfo.setStartTime(cleaningAgg.getStartTime());
                cleaningInfo.setOperatorName(cleaningAgg.getOperatorName());
            }
            vo.setCleaning(cleaningInfo);

            // 工序信息
            Long batchId = taskIdToBatchId.get(taskId);
            StepAgg stepAgg = batchId != null ? stepAggMap.get(batchId) : null;

            if (stepAgg != null) {
                ProductionProgressVO.CurrentStepInfo stepInfo = new ProductionProgressVO.CurrentStepInfo();
                stepInfo.setStepNo(stepAgg.getNo());
                stepInfo.setStepName(stepAgg.getName());
                stepInfo.setStatus(stepAgg.getStatus());
                stepInfo.setPlanStart(stepAgg.getPlanStart());
                stepInfo.setPlanEnd(stepAgg.getPlanEnd());

                fillStepStatusDisplay(stepInfo, stepAgg);

                vo.setCurrentStep(stepInfo);

                // 进度统计
                ProductionProgressVO.ProgressStats progressStats = new ProductionProgressVO.ProgressStats();
                progressStats.setTotalSteps(stepAgg.getTotalSteps());
                progressStats.setCompletedSteps(stepAgg.getCompletedSteps());
                progressStats.setProgressPercent(stepAgg.getProgressPercent());
                vo.setProgress(progressStats);
            } else {
                vo.setCurrentStep(new ProductionProgressVO.CurrentStepInfo());
                ProductionProgressVO.ProgressStats progressStats = new ProductionProgressVO.ProgressStats();
                progressStats.setTotalSteps(0);
                progressStats.setCompletedSteps(0);
                progressStats.setProgressPercent(0);
                vo.setProgress(progressStats);
            }

            result.put(taskId, vo);
        }

        return result;
    }

    @Override
    public void attachProgressSummary(List<WorkflowTaskVO> vos) {
        if (vos == null || vos.isEmpty()) return;

        // 1. 批量查询进度信息
        List<Long> taskIds = vos.stream()
                .map(WorkflowTaskVO::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (taskIds.isEmpty()) return;

        Map<Long, ProductionProgressVO> progressMap = batchGetTaskProgress(taskIds);

        // 2. 写回到 VO.extendedInfo（JSON）
        ObjectMapper mapper = JsonUtils.getMapper();
        mapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());

        for (WorkflowTaskVO vo : vos) {
            ProductionProgressVO progress = progressMap.get(vo.getId());
            if (progress != null) {
                try {
                    Map<String, Object> ext = parseExt(mapper, vo.getExtendedInfo());
                    ext.put("progressSummary", progress);
                    vo.setExtendedInfo(mapper.writeValueAsString(ext));
                } catch (Exception e) {
                    log.warn("序列化进度信息失败: taskId={}", vo.getId(), e);
                }
            }
        }
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 从任务中提取批次ID
     */
    private Long extractBatchIdFromTask(WorkflowTask task) {
        if (task != null && "PROCESS_BATCH".equals(task.getBizType())) {
            return task.getBizId();
        }
        return task != null ? task.getBizId() : null;
    }

    /**
     * 批量聚合清机摘要
     */
    private Map<Long, CleaningAgg> batchQueryCleaningAgg(List<Long> taskIds) {
        Map<Long, CleaningAgg> result = new HashMap<>();
        if (taskIds == null || taskIds.isEmpty()) return result;

        // 获取所有 taskId 对应的 batchId
        List<WorkflowTask> taskEntities = workflowTaskMapper.selectBatchIds(taskIds);
        Map<Long, Long> taskIdToBatchId = new HashMap<>();
        Map<Long, Long> batchIdToTaskId = new HashMap<>();

        for (WorkflowTask task : taskEntities) {
            Long batchId = extractBatchIdFromTask(task);
            if (batchId != null) {
                taskIdToBatchId.put(task.getId(), batchId);
                batchIdToTaskId.put(batchId, task.getId());
            }
        }

        List<Long> batchIds = new ArrayList<>(batchIdToTaskId.keySet());
        if (batchIds.isEmpty()) return result;

        // 根据 batchId 查询所有 START 记录
        LambdaQueryWrapper<ProductionOperationRecord> startQw = new LambdaQueryWrapper<>();
        startQw.in(ProductionOperationRecord::getBatchId, batchIds)
                .eq(ProductionOperationRecord::getExecType, EXEC_CLEANING)
                .eq(ProductionOperationRecord::getEventType, EVT_START)
                .eq(ProductionOperationRecord::getIsDelete, 0)
                .orderByDesc(ProductionOperationRecord::getEventTime);
        List<ProductionOperationRecord> starts = productionOperationRecordMapper.selectList(startQw);

        // 根据 batchId 查询所有 COMPLETE 记录
        LambdaQueryWrapper<ProductionOperationRecord> completeQw = new LambdaQueryWrapper<>();
        completeQw.in(ProductionOperationRecord::getBatchId, batchIds)
                .eq(ProductionOperationRecord::getExecType, EXEC_CLEANING)
                .eq(ProductionOperationRecord::getEventType, EVT_COMPLETE)
                .eq(ProductionOperationRecord::getIsDelete, 0)
                .orderByDesc(ProductionOperationRecord::getEventTime);
        List<ProductionOperationRecord> completes = productionOperationRecordMapper.selectList(completeQw);

        // 按 batchId 聚合
        Map<Long, CleaningAgg> batchAggMap = new HashMap<>();

        // 最近一次 START
        for (ProductionOperationRecord r : starts) {
            Long batchId = r.getBatchId();
            if (batchId == null) continue;
            CleaningAgg agg = batchAggMap.get(batchId);
            if (agg == null) {
                agg = new CleaningAgg();
                agg.setStartTime(toLocalDateTime(r.getEventTime()));
                agg.setOperatorName(r.getOperatorName());
                batchAggMap.put(batchId, agg);
            }
        }

        // 最近一次 COMPLETE
        for (ProductionOperationRecord r : completes) {
            Long batchId = r.getBatchId();
            if (batchId == null) continue;
            CleaningAgg agg = batchAggMap.computeIfAbsent(batchId, k -> new CleaningAgg());
            if (agg.getEndTime() == null) {
                agg.setEndTime(toLocalDateTime(r.getEventTime()));
            }
        }

        // 将 batchId 映射回 taskId
        for (Long taskId : taskIds) {
            Long batchId = taskIdToBatchId.get(taskId);
            if (batchId != null) {
                CleaningAgg agg = batchAggMap.get(batchId);
                if (agg != null) {
                    result.put(taskId, agg);
                }
            }
        }

        return result;
    }

    /**
     * 批量聚合步骤摘要
     */
    private Map<Long, StepAgg> batchQueryStepAgg(List<Long> batchIds) {
        Map<Long, StepAgg> result = new HashMap<>();
        if (batchIds == null || batchIds.isEmpty()) return result;

        // 取所有批次的步骤
        LambdaQueryWrapper<ProcessBatchStep> qw = new LambdaQueryWrapper<>();
        qw.in(ProcessBatchStep::getBatchId, batchIds)
                .eq(ProcessBatchStep::getIsDeleted, 0)
                .orderByAsc(ProcessBatchStep::getBatchId)
                .orderByAsc(ProcessBatchStep::getSequenceNo);
        List<ProcessBatchStep> steps = processBatchStepMapper.selectList(qw);

        // 统计每个批次的工序数量
        Map<Long, Integer> totalMap = new HashMap<>();
        Map<Long, Integer> completedMap = new HashMap<>();

        for (ProcessBatchStep s : steps) {
            totalMap.merge(s.getBatchId(), 1, Integer::sum);
            if (STEP_STATUS_COMPLETED.equals(s.getStatus())) {
                completedMap.merge(s.getBatchId(), 1, Integer::sum);
            }
        }

        // 先找进行中
        Set<Long> handled = new HashSet<>();
        for (ProcessBatchStep s : steps) {
            if ("IN_PROGRESS".equals(s.getStatus())) {
                StepAgg agg = createStepAgg(s, totalMap, completedMap);
                result.put(s.getBatchId(), agg);
                handled.add(s.getBatchId());
            }
        }

        // 未进行中则找第一道未完成
        for (ProcessBatchStep s : steps) {
            if (handled.contains(s.getBatchId())) continue;
            if (!STEP_STATUS_COMPLETED.equals(s.getStatus())) {
                StepAgg agg = createStepAgg(s, totalMap, completedMap);
                result.put(s.getBatchId(), agg);
                handled.add(s.getBatchId());
            }
        }

        return result;
    }

    /**
     * 创建 StepAgg 并填充统计数据
     */
    private StepAgg createStepAgg(ProcessBatchStep s, Map<Long, Integer> totalMap,
                                  Map<Long, Integer> completedMap) {
        StepAgg agg = new StepAgg();
        agg.setNo(s.getSequenceNo());
        agg.setName(s.getOperationName());
        agg.setStatus(s.getStatus());
        agg.setPlanStart(s.getPlanStart());
        agg.setPlanEnd(s.getPlanEnd());
        agg.setNeedInspection(s.getNeedInspection());

        int total = totalMap.getOrDefault(s.getBatchId(), 0);
        int completed = completedMap.getOrDefault(s.getBatchId(), 0);
        agg.setTotalSteps(total);
        agg.setCompletedSteps(completed);
        agg.setProgressPercent(total > 0 ? completed * 100 / total : 0);

        return agg;
    }

    /**
     * 填充工序状态显示信息
     */
    private void fillStepStatusDisplay(ProductionProgressVO.CurrentStepInfo stepInfo, StepAgg stepAgg) {
        String status = stepAgg.getStatus();
        Integer needInspection = stepAgg.getNeedInspection();
        boolean needsQA = needInspection != null && needInspection == 1;

        stepInfo.setNeedsQualityCheck(needsQA);

        switch (status) {
            case "PENDING_QA":
                stepInfo.setStatusDisplay("已完成（待质检）");
                stepInfo.setStatusDescription("生产已完成，等待质检员检验");
                stepInfo.setIsProductionCompleted(true);
                break;

            case STEP_STATUS_COMPLETED:
                stepInfo.setStatusDisplay("已完成");
                stepInfo.setStatusDescription(needsQA ? "生产和质检均已完成" : "工序已完成");
                stepInfo.setIsProductionCompleted(true);
                break;

            case "IN_PROGRESS":
                stepInfo.setStatusDisplay("进行中");
                stepInfo.setStatusDescription("工序正在进行");
                stepInfo.setIsProductionCompleted(false);
                break;

            case "READY":
                stepInfo.setStatusDisplay("待开始");
                stepInfo.setStatusDescription("可以开始此工序");
                stepInfo.setIsProductionCompleted(false);
                break;

            case "PLANNED":
                stepInfo.setStatusDisplay("计划中");
                stepInfo.setStatusDescription("等待前序工序完成");
                stepInfo.setIsProductionCompleted(false);
                break;

            default:
                stepInfo.setStatusDisplay(status);
                stepInfo.setStatusDescription("");
                stepInfo.setIsProductionCompleted(false);
        }
    }

    /**
     * 解析 JSON 为 Map
     */
    private Map<String, Object> parseExt(ObjectMapper mapper, String json) {
        try {
            if (json == null || json.trim().isEmpty()) return new HashMap<>();
            return mapper.readValue(json, HashMap.class);
        } catch (Exception e) {
            return new HashMap<>();
        }
    }

    /**
     * Date 转 LocalDateTime
     */
    private LocalDateTime toLocalDateTime(Date date) {
        if (date == null) return null;
        return date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime();
    }

    // ==================== 内部类 ====================

    @Data
    private static class CleaningAgg {
        private LocalDateTime startTime;
        private LocalDateTime endTime;
        private String operatorName;
    }

    @Data
    private static class StepAgg {
        private Integer no;
        private String name;
        private String status;
        private LocalDateTime planStart;
        private LocalDateTime planEnd;
        private Integer totalSteps;
        private Integer completedSteps;
        private Integer progressPercent;
        private Integer needInspection;
    }
}